// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Web;
using System.Web.Hosting;
using System.Web.Profile;
using BlueOnionSoftware.Bloget.Providers.Data;

namespace BlueOnionSoftware.Bloget.Providers
{
    public class XmlProfileProvider : ProfileProvider
    {
        private string dataStorePath;
        private string applicationName;

        public string DataStorePath
        {
            get { return dataStorePath; }
            set { dataStorePath = value; }
        }

        private string DataStoreFile
        {
            get
            {
                string path;

                if (HttpContext.Current != null)
                {
                    path = HttpContext.Current.Server.MapPath(DataStorePath);
                }

                else
                {
                    path = HostingEnvironment.ApplicationPhysicalPath;
                    var dataStorePath = DataStorePath.Replace("~/", string.Empty);
                    path = Path.Combine(path, dataStorePath);
                }

                return Path.Combine(path, string.Format("{0}_Profiles.xml", applicationName));
            }
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            Throw.IfNull(config, "config");

            if (String.IsNullOrEmpty(name))
            {
                name = "XmlProfileProvider";
            }

            base.Initialize(name, config);

            dataStorePath = String.IsNullOrEmpty(config["dataStorePath"]) ? "~/App_Data" : config["dataStorePath"];
            applicationName = String.IsNullOrEmpty(config["applicationName"]) ? "Bloget" : config["applicationName"];
        }

        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            var toBeRemoved = new List<Profile>();

            foreach (var profile in profiles)
            {
                switch (authenticationOption)
                {
                    case ProfileAuthenticationOption.All:
                        if (profile.LastActivityDate <= userInactiveSinceDate)
                        {
                            toBeRemoved.Add(profile);
                        }
                        break;

                    case ProfileAuthenticationOption.Anonymous:
                        if (profile.LastActivityDate <= userInactiveSinceDate && profile.IsAnonymous)
                        {
                            toBeRemoved.Add(profile);
                        }
                        break;

                    case ProfileAuthenticationOption.Authenticated:
                        if (profile.LastActivityDate <= userInactiveSinceDate && !profile.IsAnonymous)
                        {
                            toBeRemoved.Add(profile);
                        }
                        break;
                }
            }

            for (var i = 0; i < toBeRemoved.Count; i++)
            {
                profiles.Remove(toBeRemoved[i]);
            }

            return toBeRemoved.Count;
        }

        public override int DeleteProfiles(string[] usernames)
        {
            var counter = 0;
            var profiles = ProfileCollection.Load(DataStoreFile);

            foreach (var name in usernames)
            {
                var p = profiles.FindByUserName(name, ProfileAuthenticationOption.All);

                if (p.Count > 0)
                {
                    for (var i = 0; i < p.Count; i++)
                    {
                        profiles.Remove(p[i]);
                        counter++;
                    }
                }
            }

            profiles.Save(DataStoreFile);
            return counter;
        }

        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {
            var usernames = new List<string>();

            foreach (ProfileInfo pi in profiles)
            {
                usernames.Add(pi.UserName);
            }

            return DeleteProfiles(usernames.ToArray());
        }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            var pic = profiles.CreateProfileInfoCollection(authenticationOption);
            var lst = new List<ProfileInfo>();

            foreach (ProfileInfo p in pic)
            {
                if (p.UserName.Contains(usernameToMatch))
                {
                    lst.Add(p);
                }
            }

            totalRecords = lst.Count;

            var output = new ProfileInfoCollection();
            for (var i = (pageIndex*pageSize); i < ((pageIndex*pageSize) + pageSize); i++)
            {
                if (lst.Count < i)
                {
                    break;
                }
                output.Add(lst[i]);
            }

            return output;
        }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);

            var pic = profiles.CreateProfileInfoCollection(authenticationOption);
            var lst = new List<ProfileInfo>();

            foreach (ProfileInfo pi in pic)
            {
                if (pi.LastActivityDate <= userInactiveSinceDate)
                {
                    lst.Add(pi);
                }
            }

            totalRecords = lst.Count;
            var counter = 0;

            var newPic = new ProfileInfoCollection();

            foreach (var pi in lst)
            {
                if (counter > (pageIndex*pageSize) && counter < ((pageIndex*pageSize) + pageSize))
                {
                    newPic.Add(pi);
                }
                counter++;
            }

            return newPic;
        }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            var pic = profiles.CreateProfileInfoCollection(authenticationOption);
            var newPic = new ProfileInfoCollection();

            totalRecords = pic.Count;
            var counter = 0;

            foreach (ProfileInfo pi in pic)
            {
                if (counter > (pageIndex*pageSize) && counter < ((pageIndex*pageSize) + pageSize))
                {
                    newPic.Add(pi);
                }

                counter++;
            }

            return newPic;
        }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            var pic = profiles.CreateProfileInfoCollection(authenticationOption);
            var counter = 0;

            foreach (ProfileInfo p in pic)
            {
                if (p.LastActivityDate <= userInactiveSinceDate)
                {
                    counter++;
                }
            }

            return counter;
        }

        public override string ApplicationName
        {
            get { return applicationName; }
            set { applicationName = value; }
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            Collection<Profile> profile = null;

            var userID = context["UserName"].ToString();
            var authenticated = Convert.ToBoolean(context["IsAuthenticated"]);

            if (authenticated)
            {
                profile = profiles.FindByUserName(userID, ProfileAuthenticationOption.Authenticated);
            }

            else
            {
                profile = profiles.FindByUserName(userID, ProfileAuthenticationOption.Anonymous);
            }


            var spvc = new SettingsPropertyValueCollection();
            Profile prof = null;

            if (profile.Count > 0)
            {
                prof = profile[0];
            }


            foreach (SettingsProperty prop in collection)
            {
                var val = new SettingsPropertyValue(prop);

                if (prof != null && prof.Properties.Contains(prop.Name))
                {
                    if (val.Deserialized)
                    {
                        val.PropertyValue = prof.Properties[prop.Name].Value;
                    }

                    else
                    {
                        val.SerializedValue = prof.Properties[prop.Name].Value;
                        if (prop.SerializeAs == SettingsSerializeAs.ProviderSpecific)
                        {
                            val.PropertyValue = Convert.ChangeType(val.SerializedValue, prop.PropertyType);
                        }
                    }

                    val.IsDirty = false;
                }

                spvc.Add(val);
            }

            return spvc;
        }

        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
        {
            var profiles = ProfileCollection.Load(DataStoreFile);
            Collection<Profile> profile = null;

            var userID = context["UserName"].ToString();
            var authenticated = Convert.ToBoolean(context["IsAuthenticated"]);

            if (authenticated)
            {
                profile = profiles.FindByUserName(userID, ProfileAuthenticationOption.Authenticated);
            }

            else
            {
                profile = profiles.FindByUserName(userID, ProfileAuthenticationOption.Anonymous);
            }

            Profile p = null;

            if (profile.Count > 0)
            {
                p = profile[0];
            }

            else
            {
                p = new Profile();
                p.IsAnonymous = !authenticated;
                p.UserName = userID;
                profiles.Add(p);
            }

            foreach (SettingsPropertyValue val in collection)
            {
                if (val.SerializedValue != null)
                {
                    if (p.Properties.Contains(val.Name))
                    {
                        p.Properties[val.Name].Value = val.SerializedValue;
                    }

                    else
                    {
                        var pro = new ProfileProperty(val.Name);
                        pro.Value = val.SerializedValue;
                        p.Properties.Add(pro);
                    }
                }
            }

            profiles.Save(DataStoreFile);
        }
    }
}